﻿using System;
using System.Collections.Generic;
using System.Reflection;
using Mono.Cecil.Metadata;
using Mono.Collections.Generic;

namespace Mono.Cecil
{
	// Token: 0x02000087 RID: 135
	public class DefaultReflectionImporter : IReflectionImporter
	{
		// Token: 0x06000508 RID: 1288 RVA: 0x00003DD3 File Offset: 0x00001FD3
		public DefaultReflectionImporter(ModuleDefinition module)
		{
			Mixin.CheckModule(module);
			this.module = module;
		}

		// Token: 0x06000509 RID: 1289 RVA: 0x0001D1D8 File Offset: 0x0001B3D8
		private TypeReference ImportType(Type type, ImportGenericContext context)
		{
			return this.ImportType(type, context, DefaultReflectionImporter.ImportGenericKind.Open);
		}

		// Token: 0x0600050A RID: 1290 RVA: 0x0001D1F4 File Offset: 0x0001B3F4
		private TypeReference ImportType(Type type, ImportGenericContext context, DefaultReflectionImporter.ImportGenericKind import_kind)
		{
			bool flag = DefaultReflectionImporter.IsTypeSpecification(type) || DefaultReflectionImporter.ImportOpenGenericType(type, import_kind);
			TypeReference result;
			if (flag)
			{
				result = this.ImportTypeSpecification(type, context);
			}
			else
			{
				TypeReference typeReference = new TypeReference(string.Empty, type.Name, this.module, this.ImportScope(type), type.IsValueType);
				typeReference.etype = DefaultReflectionImporter.ImportElementType(type);
				bool flag2 = DefaultReflectionImporter.IsNestedType(type);
				if (flag2)
				{
					typeReference.DeclaringType = this.ImportType(type.DeclaringType, context, import_kind);
				}
				else
				{
					typeReference.Namespace = (type.Namespace ?? string.Empty);
				}
				bool isGenericType = type.IsGenericType;
				if (isGenericType)
				{
					DefaultReflectionImporter.ImportGenericParameters(typeReference, type.GetGenericArguments());
				}
				result = typeReference;
			}
			return result;
		}

		// Token: 0x0600050B RID: 1291 RVA: 0x0001D2AC File Offset: 0x0001B4AC
		protected virtual IMetadataScope ImportScope(Type type)
		{
			return this.ImportScope(type.Assembly);
		}

		// Token: 0x0600050C RID: 1292 RVA: 0x0001D2CC File Offset: 0x0001B4CC
		private static bool ImportOpenGenericType(Type type, DefaultReflectionImporter.ImportGenericKind import_kind)
		{
			return type.IsGenericType && type.IsGenericTypeDefinition && import_kind == DefaultReflectionImporter.ImportGenericKind.Open;
		}

		// Token: 0x0600050D RID: 1293 RVA: 0x0001D2F8 File Offset: 0x0001B4F8
		private static bool ImportOpenGenericMethod(MethodBase method, DefaultReflectionImporter.ImportGenericKind import_kind)
		{
			return method.IsGenericMethod && method.IsGenericMethodDefinition && import_kind == DefaultReflectionImporter.ImportGenericKind.Open;
		}

		// Token: 0x0600050E RID: 1294 RVA: 0x0001D324 File Offset: 0x0001B524
		private static bool IsNestedType(Type type)
		{
			return type.IsNested;
		}

		// Token: 0x0600050F RID: 1295 RVA: 0x0001D33C File Offset: 0x0001B53C
		private TypeReference ImportTypeSpecification(Type type, ImportGenericContext context)
		{
			bool isByRef = type.IsByRef;
			TypeReference result;
			if (isByRef)
			{
				result = new ByReferenceType(this.ImportType(type.GetElementType(), context));
			}
			else
			{
				bool isPointer = type.IsPointer;
				if (isPointer)
				{
					result = new PointerType(this.ImportType(type.GetElementType(), context));
				}
				else
				{
					bool isArray = type.IsArray;
					if (isArray)
					{
						result = new ArrayType(this.ImportType(type.GetElementType(), context), type.GetArrayRank());
					}
					else
					{
						bool isGenericType = type.IsGenericType;
						if (isGenericType)
						{
							result = this.ImportGenericInstance(type, context);
						}
						else
						{
							bool isGenericParameter = type.IsGenericParameter;
							if (!isGenericParameter)
							{
								throw new NotSupportedException(type.FullName);
							}
							result = DefaultReflectionImporter.ImportGenericParameter(type, context);
						}
					}
				}
			}
			return result;
		}

		// Token: 0x06000510 RID: 1296 RVA: 0x0001D3E8 File Offset: 0x0001B5E8
		private static TypeReference ImportGenericParameter(Type type, ImportGenericContext context)
		{
			bool isEmpty = context.IsEmpty;
			if (isEmpty)
			{
				throw new InvalidOperationException();
			}
			bool flag = type.DeclaringMethod != null;
			TypeReference result;
			if (flag)
			{
				result = context.MethodParameter(DefaultReflectionImporter.NormalizeMethodName(type.DeclaringMethod), type.GenericParameterPosition);
			}
			else
			{
				bool flag2 = type.DeclaringType != null;
				if (!flag2)
				{
					throw new InvalidOperationException();
				}
				result = context.TypeParameter(DefaultReflectionImporter.NormalizeTypeFullName(type.DeclaringType), type.GenericParameterPosition);
			}
			return result;
		}

		// Token: 0x06000511 RID: 1297 RVA: 0x0001D464 File Offset: 0x0001B664
		private static string NormalizeMethodName(MethodBase method)
		{
			return DefaultReflectionImporter.NormalizeTypeFullName(method.DeclaringType) + "." + method.Name;
		}

		// Token: 0x06000512 RID: 1298 RVA: 0x0001D494 File Offset: 0x0001B694
		private static string NormalizeTypeFullName(Type type)
		{
			bool flag = DefaultReflectionImporter.IsNestedType(type);
			string result;
			if (flag)
			{
				result = DefaultReflectionImporter.NormalizeTypeFullName(type.DeclaringType) + "/" + type.Name;
			}
			else
			{
				result = type.FullName;
			}
			return result;
		}

		// Token: 0x06000513 RID: 1299 RVA: 0x0001D4D4 File Offset: 0x0001B6D4
		private TypeReference ImportGenericInstance(Type type, ImportGenericContext context)
		{
			TypeReference typeReference = this.ImportType(type.GetGenericTypeDefinition(), context, DefaultReflectionImporter.ImportGenericKind.Definition);
			Type[] genericArguments = type.GetGenericArguments();
			GenericInstanceType genericInstanceType = new GenericInstanceType(typeReference, genericArguments.Length);
			Collection<TypeReference> genericArguments2 = genericInstanceType.GenericArguments;
			context.Push(typeReference);
			TypeReference result;
			try
			{
				for (int i = 0; i < genericArguments.Length; i++)
				{
					genericArguments2.Add(this.ImportType(genericArguments[i], context));
				}
				result = genericInstanceType;
			}
			finally
			{
				context.Pop();
			}
			return result;
		}

		// Token: 0x06000514 RID: 1300 RVA: 0x0001D560 File Offset: 0x0001B760
		private static bool IsTypeSpecification(Type type)
		{
			return type.HasElementType || DefaultReflectionImporter.IsGenericInstance(type) || type.IsGenericParameter;
		}

		// Token: 0x06000515 RID: 1301 RVA: 0x0001D58C File Offset: 0x0001B78C
		private static bool IsGenericInstance(Type type)
		{
			return type.IsGenericType && !type.IsGenericTypeDefinition;
		}

		// Token: 0x06000516 RID: 1302 RVA: 0x0001D5B4 File Offset: 0x0001B7B4
		private static ElementType ImportElementType(Type type)
		{
			ElementType elementType;
			bool flag = !DefaultReflectionImporter.type_etype_mapping.TryGetValue(type, out elementType);
			ElementType result;
			if (flag)
			{
				result = ElementType.None;
			}
			else
			{
				result = elementType;
			}
			return result;
		}

		// Token: 0x06000517 RID: 1303 RVA: 0x0001D5E0 File Offset: 0x0001B7E0
		protected AssemblyNameReference ImportScope(Assembly assembly)
		{
			return this.ImportReference(assembly.GetName());
		}

		// Token: 0x06000518 RID: 1304 RVA: 0x0001D600 File Offset: 0x0001B800
		public virtual AssemblyNameReference ImportReference(AssemblyName name)
		{
			Mixin.CheckName(name);
			AssemblyNameReference assemblyNameReference;
			bool flag = this.TryGetAssemblyNameReference(name, out assemblyNameReference);
			AssemblyNameReference result;
			if (flag)
			{
				result = assemblyNameReference;
			}
			else
			{
				assemblyNameReference = new AssemblyNameReference(name.Name, name.Version)
				{
					PublicKeyToken = name.GetPublicKeyToken(),
					Culture = name.CultureInfo.Name,
					HashAlgorithm = (AssemblyHashAlgorithm)name.HashAlgorithm
				};
				this.module.AssemblyReferences.Add(assemblyNameReference);
				result = assemblyNameReference;
			}
			return result;
		}

		// Token: 0x06000519 RID: 1305 RVA: 0x0001D67C File Offset: 0x0001B87C
		private bool TryGetAssemblyNameReference(AssemblyName name, out AssemblyNameReference assembly_reference)
		{
			Collection<AssemblyNameReference> assemblyReferences = this.module.AssemblyReferences;
			for (int i = 0; i < assemblyReferences.Count; i++)
			{
				AssemblyNameReference assemblyNameReference = assemblyReferences[i];
				bool flag = name.FullName != assemblyNameReference.FullName;
				if (!flag)
				{
					assembly_reference = assemblyNameReference;
					return true;
				}
			}
			assembly_reference = null;
			return false;
		}

		// Token: 0x0600051A RID: 1306 RVA: 0x0001D6E0 File Offset: 0x0001B8E0
		private FieldReference ImportField(FieldInfo field, ImportGenericContext context)
		{
			TypeReference typeReference = this.ImportType(field.DeclaringType, context);
			bool flag = DefaultReflectionImporter.IsGenericInstance(field.DeclaringType);
			if (flag)
			{
				field = DefaultReflectionImporter.ResolveFieldDefinition(field);
			}
			context.Push(typeReference);
			FieldReference result;
			try
			{
				result = new FieldReference
				{
					Name = field.Name,
					DeclaringType = typeReference,
					FieldType = this.ImportType(field.FieldType, context)
				};
			}
			finally
			{
				context.Pop();
			}
			return result;
		}

		// Token: 0x0600051B RID: 1307 RVA: 0x0001D76C File Offset: 0x0001B96C
		private static FieldInfo ResolveFieldDefinition(FieldInfo field)
		{
			return field.Module.ResolveField(field.MetadataToken);
		}

		// Token: 0x0600051C RID: 1308 RVA: 0x0001D790 File Offset: 0x0001B990
		private static MethodBase ResolveMethodDefinition(MethodBase method)
		{
			return method.Module.ResolveMethod(method.MetadataToken);
		}

		// Token: 0x0600051D RID: 1309 RVA: 0x0001D7B4 File Offset: 0x0001B9B4
		private MethodReference ImportMethod(MethodBase method, ImportGenericContext context, DefaultReflectionImporter.ImportGenericKind import_kind)
		{
			bool flag = DefaultReflectionImporter.IsMethodSpecification(method) || DefaultReflectionImporter.ImportOpenGenericMethod(method, import_kind);
			MethodReference result;
			if (flag)
			{
				result = this.ImportMethodSpecification(method, context);
			}
			else
			{
				TypeReference declaringType = this.ImportType(method.DeclaringType, context);
				bool flag2 = DefaultReflectionImporter.IsGenericInstance(method.DeclaringType);
				if (flag2)
				{
					method = DefaultReflectionImporter.ResolveMethodDefinition(method);
				}
				MethodReference methodReference = new MethodReference
				{
					Name = method.Name,
					HasThis = DefaultReflectionImporter.HasCallingConvention(method, CallingConventions.HasThis),
					ExplicitThis = DefaultReflectionImporter.HasCallingConvention(method, CallingConventions.ExplicitThis),
					DeclaringType = this.ImportType(method.DeclaringType, context, DefaultReflectionImporter.ImportGenericKind.Definition)
				};
				bool flag3 = DefaultReflectionImporter.HasCallingConvention(method, CallingConventions.VarArgs);
				if (flag3)
				{
					methodReference.CallingConvention &= MethodCallingConvention.VarArg;
				}
				bool isGenericMethod = method.IsGenericMethod;
				if (isGenericMethod)
				{
					DefaultReflectionImporter.ImportGenericParameters(methodReference, method.GetGenericArguments());
				}
				context.Push(methodReference);
				try
				{
					MethodInfo methodInfo = method as MethodInfo;
					methodReference.ReturnType = ((methodInfo != null) ? this.ImportType(methodInfo.ReturnType, context) : this.ImportType(typeof(void), default(ImportGenericContext)));
					ParameterInfo[] parameters = method.GetParameters();
					Collection<ParameterDefinition> parameters2 = methodReference.Parameters;
					for (int i = 0; i < parameters.Length; i++)
					{
						parameters2.Add(new ParameterDefinition(this.ImportType(parameters[i].ParameterType, context)));
					}
					methodReference.DeclaringType = declaringType;
					result = methodReference;
				}
				finally
				{
					context.Pop();
				}
			}
			return result;
		}

		// Token: 0x0600051E RID: 1310 RVA: 0x0001D944 File Offset: 0x0001BB44
		private static void ImportGenericParameters(IGenericParameterProvider provider, Type[] arguments)
		{
			Collection<GenericParameter> genericParameters = provider.GenericParameters;
			for (int i = 0; i < arguments.Length; i++)
			{
				genericParameters.Add(new GenericParameter(arguments[i].Name, provider));
			}
		}

		// Token: 0x0600051F RID: 1311 RVA: 0x0001D980 File Offset: 0x0001BB80
		private static bool IsMethodSpecification(MethodBase method)
		{
			return method.IsGenericMethod && !method.IsGenericMethodDefinition;
		}

		// Token: 0x06000520 RID: 1312 RVA: 0x0001D9A8 File Offset: 0x0001BBA8
		private MethodReference ImportMethodSpecification(MethodBase method, ImportGenericContext context)
		{
			MethodInfo methodInfo = method as MethodInfo;
			bool flag = methodInfo == null;
			if (flag)
			{
				throw new InvalidOperationException();
			}
			MethodReference methodReference = this.ImportMethod(methodInfo.GetGenericMethodDefinition(), context, DefaultReflectionImporter.ImportGenericKind.Definition);
			GenericInstanceMethod genericInstanceMethod = new GenericInstanceMethod(methodReference);
			Type[] genericArguments = method.GetGenericArguments();
			Collection<TypeReference> genericArguments2 = genericInstanceMethod.GenericArguments;
			context.Push(methodReference);
			MethodReference result;
			try
			{
				for (int i = 0; i < genericArguments.Length; i++)
				{
					genericArguments2.Add(this.ImportType(genericArguments[i], context));
				}
				result = genericInstanceMethod;
			}
			finally
			{
				context.Pop();
			}
			return result;
		}

		// Token: 0x06000521 RID: 1313 RVA: 0x0001DA4C File Offset: 0x0001BC4C
		private static bool HasCallingConvention(MethodBase method, CallingConventions conventions)
		{
			return (method.CallingConvention & conventions) > (CallingConventions)0;
		}

		// Token: 0x06000522 RID: 1314 RVA: 0x0001DA6C File Offset: 0x0001BC6C
		public virtual TypeReference ImportReference(Type type, IGenericParameterProvider context)
		{
			Mixin.CheckType(type);
			return this.ImportType(type, ImportGenericContext.For(context), (context != null) ? DefaultReflectionImporter.ImportGenericKind.Open : DefaultReflectionImporter.ImportGenericKind.Definition);
		}

		// Token: 0x06000523 RID: 1315 RVA: 0x0001DA9C File Offset: 0x0001BC9C
		public virtual FieldReference ImportReference(FieldInfo field, IGenericParameterProvider context)
		{
			Mixin.CheckField(field);
			return this.ImportField(field, ImportGenericContext.For(context));
		}

		// Token: 0x06000524 RID: 1316 RVA: 0x0001DAC4 File Offset: 0x0001BCC4
		public virtual MethodReference ImportReference(MethodBase method, IGenericParameterProvider context)
		{
			Mixin.CheckMethod(method);
			return this.ImportMethod(method, ImportGenericContext.For(context), (context != null) ? DefaultReflectionImporter.ImportGenericKind.Open : DefaultReflectionImporter.ImportGenericKind.Definition);
		}

		// Token: 0x04000143 RID: 323
		protected readonly ModuleDefinition module;

		// Token: 0x04000144 RID: 324
		private static readonly Dictionary<Type, ElementType> type_etype_mapping = new Dictionary<Type, ElementType>(18)
		{
			{
				typeof(void),
				ElementType.Void
			},
			{
				typeof(bool),
				ElementType.Boolean
			},
			{
				typeof(char),
				ElementType.Char
			},
			{
				typeof(sbyte),
				ElementType.I1
			},
			{
				typeof(byte),
				ElementType.U1
			},
			{
				typeof(short),
				ElementType.I2
			},
			{
				typeof(ushort),
				ElementType.U2
			},
			{
				typeof(int),
				ElementType.I4
			},
			{
				typeof(uint),
				ElementType.U4
			},
			{
				typeof(long),
				ElementType.I8
			},
			{
				typeof(ulong),
				ElementType.U8
			},
			{
				typeof(float),
				ElementType.R4
			},
			{
				typeof(double),
				ElementType.R8
			},
			{
				typeof(string),
				ElementType.String
			},
			{
				typeof(TypedReference),
				ElementType.TypedByRef
			},
			{
				typeof(IntPtr),
				ElementType.I
			},
			{
				typeof(UIntPtr),
				ElementType.U
			},
			{
				typeof(object),
				ElementType.Object
			}
		};

		// Token: 0x02000088 RID: 136
		private enum ImportGenericKind
		{
			// Token: 0x04000146 RID: 326
			Definition,
			// Token: 0x04000147 RID: 327
			Open
		}
	}
}
